/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package text_classification;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author robertgunawan
 */
public class naive_bayes {

   //penyimpan data hasil learning
   public HashMap<String , class_value> nb = new HashMap<String, class_value>();

   //penyimpan data hasil testing
   public HashMap<String, HashMap<String, Integer>> hasil = new HashMap<String, HashMap<String, Integer>>();

   //training
   public ArrayList<String> trainingNegatif = new ArrayList<String>();
   public ArrayList<String> trainingNetral = new ArrayList<String>();
   public ArrayList<String> trainingPositif = new ArrayList<String>();

   //test
   public ArrayList<String> testNegatif = new ArrayList<String>();
   public ArrayList<String> testNetral = new ArrayList<String>();
   public ArrayList<String> testPositif = new ArrayList<String>();

   public ArrayList<String> ReadFile(String namaFile)
   {
        ArrayList<String> result = new ArrayList<String>();
        File file = new File(namaFile);
        try {
            Scanner inNegatif = new Scanner(file);
            while(inNegatif.hasNext())
            {
                result.add(inNegatif.nextLine());
            }
            inNegatif.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(naive_bayes.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
   }

   public static void SaveFile (String nama, ArrayList<String> aaa)
    {
        //kamus lokal
        File f = new File(nama);

        int i;
        if(!f.canWrite())
        {
            File fi = new File("data");
            fi.mkdir();
        }

        //algoritma
        try
        {
        FileWriter in = new FileWriter(f);
        PrintWriter out = new PrintWriter(in);
        in.flush();
        for(i=0;i<aaa.size();i++)
        {
            out.println(aaa.get(i));
        }
        out.close();
        }catch (IOException ex)
            {
                Logger.getLogger(naive_bayes.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

   public ArrayList<ArrayList<String>> pecah(ArrayList<String> masukan)
   //pecah per 2/3 untuk training dan 1/3 untuk test
   {
       ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
       ArrayList<String> train = new ArrayList<String>();
       ArrayList<String> test = new ArrayList<String>();
       Random rn = new Random();
       int random;
       int c_Train = 0;
       int c_Test = 0;
       double max_Test = masukan.size() / 3;
       double max_Train = masukan.size() - max_Test;

       //System.out.println("Test:"+max_Test);
       //System.out.println("Train:"+max_Train);

       for(int i=0;i<masukan.size();i++)
       {
           random = rn.nextInt(2) % 2;
           if(random == 0 && c_Train < max_Train)
           {
                train.add(masukan.get(i));
                c_Train++;
           }
           else if (random == 1 && c_Test < max_Test)
           {
                test.add(masukan.get(i));
                c_Test++;
           }
           else
           {
               
               if(random == 1)
               {
                   train.add(masukan.get(i));
                   c_Train++;
               }
               else if(random == 0)
               {
                   test.add(masukan.get(i));
                   c_Test++;
               }
           }
       }
       result.add(train);
       result.add(test);
       return result;
   }

   public naive_bayes(String negatif, String netral, String positif, boolean isLaplace)
   {
       nb = new HashMap<String, class_value>(); //instansiasi nilai nb
       //read semua file ke arrayList
       ArrayList<String> allNegatif = ReadFile(negatif);
       ArrayList<String> allNetral = ReadFile(netral);
       ArrayList<String> allPositif = ReadFile(positif);

       /*
       //parse ke training dan test
       //negatif
       ArrayList<ArrayList<String>> tempNegatif = pecah(allNegatif);
       //netral
       ArrayList<ArrayList<String>> tempNetral = pecah(allNetral);
       //positif
       ArrayList<ArrayList<String>> tempPositif = pecah(allPositif);

       //save dulu ke external_file
       SaveFile("data/train_Negatif.txt",tempNegatif.get(0));
       SaveFile("data/test_Negatif.txt",tempNegatif.get(1));
       SaveFile("data/train_Netral.txt",tempNetral.get(0));
       SaveFile("data/test_Netral.txt",tempNetral.get(1));
       SaveFile("data/train_Positif.txt",tempPositif.get(0));
       SaveFile("data/test_Positif.txt",tempPositif.get(1));
        * */

       //learning
       String token[];
       //negatif
       for(int i=0;i<allNegatif.size();i++)
       {
           token = allNegatif.get(i).split(" ");
           for(int j=0;j<token.length;j++)
           {
               if(!nb.containsKey(token[j]))
               {
                   class_value cv = new class_value(isLaplace);
                   cv.increment('-');
                   nb.put(token[j], cv);
               }
               else
               {
                   nb.get(token[j]).increment('-');
               }
           }
       }
       //netral
       for(int i=0;i<allNetral.size();i++)
       {
           token = allNetral.get(i).split(" ");
           for(int j=0;j<token.length;j++)
           {
               if(!nb.containsKey(token[j]))
               {
                   class_value cv = new class_value(isLaplace);
                   cv.increment('#');
                   nb.put(token[j], cv);
               }
               else
               {
                   nb.get(token[j]).increment('#');
               }
           }
       }
       //positif
       for(int i=0;i<allPositif.size();i++)
       {
           token = allPositif.get(i).split(" ");
           for(int j=0;j<token.length;j++)
           {
               if(!nb.containsKey(token[j]))
               {
                   class_value cv = new class_value(isLaplace);
                   cv.increment('+');
                   nb.put(token[j], cv);
               }
               else
               {
                   nb.get(token[j]).increment('+');
               }
           }
       }
   }

   public String classify(String input)
   {
       String result = "";
       String token[] = input.split(" ");
       double positive = 1;
       double negative = 1;
       double netral = 1;
       double value = 0.2;

       for(int i=0;i<token.length;i++)
       {
           try
           {
               positive = positive * nb.get(token[i]).getPositif() / nb.get(token[i]).getTotal();
               negative = negative * nb.get(token[i]).getNegatif() / nb.get(token[i]).getTotal();
               netral = netral * nb.get(token[i]).getNetral() / nb.get(token[i]).getTotal();
           }catch(Exception e)
           {
               positive = positive * value;
               negative = negative * value;
               netral = netral * value;
           }
       }

       //mulai cek 1-1
       if(negative > positive)
       {
            if(negative > netral)
            {
                result = "negative";
            }
            else
            {
                result = "netral";
            }
       }
       else //negative <= positive
       {
            if(positive > netral)
            {
                result = "positive";
            }
            else
            {
                result = "netral";
            }
       }
       return result;
   }

   public void doClassification(String negatif, String netral, String positif)
   {
       //masukkan ke dalam arraylist dulu semuanya
       ArrayList<String> isiNegatif = ReadFile(negatif);
       ArrayList<String> isiNetral = ReadFile(netral);
       ArrayList<String> isiPositif = ReadFile(positif);

       HashMap<String, Integer> tempN = new HashMap<String, Integer>();
       tempN.put("negative", 0);
       tempN.put("netral", 0);
       tempN.put("positive", 0);

       HashMap<String, Integer> tempH = new HashMap<String, Integer>();
       tempH.put("negative", 0);
       tempH.put("netral", 0);
       tempH.put("positive", 0);

       HashMap<String, Integer> tempP = new HashMap<String, Integer>();
       tempP.put("negative", 0);
       tempP.put("netral", 0);
       tempP.put("positive", 0);

       hasil.clear();
       hasil.put("negative", tempN);
       hasil.put("netral", tempH);
       hasil.put("positive", tempP);

       String dest = "";
       //untuk setiap negatif yang ada
       for(int i=0;i<isiNegatif.size();i++)
       {
           dest = classify(isiNegatif.get(i));
           hasil.get("negative").put(dest, hasil.get("negative").get(dest)+1);
       }
       //untuk setiap netral yang ada
       for(int i=0;i<isiNetral.size();i++)
       {
           dest = classify(isiNetral.get(i));
           hasil.get("netral").put(dest, hasil.get("netral").get(dest)+1);
       }
       //untuk setiap positif yanga da
       for(int i=0;i<isiPositif.size();i++)
       {
           dest = classify(isiPositif.get(i));
           hasil.get("positive").put(dest, hasil.get("positive").get(dest)+1);
       }
   }

   public void doPrintConfusionMatrix()
   {
       int a,b,c;
       System.out.println("    "+"a\tb\tc");
       a = hasil.get("negative").get("negative");
       b = hasil.get("negative").get("netral");
       c = hasil.get("negative").get("positive");
       System.out.println("a : "+a+"\t"+b+"\t"+c);
       a = hasil.get("netral").get("negative");
       b = hasil.get("netral").get("netral");
       c = hasil.get("netral").get("positive");
       System.out.println("b : "+a+"\t"+b+"\t"+c);
       a = hasil.get("positive").get("negative");
       b = hasil.get("positive").get("netral");
       c = hasil.get("positive").get("positive");
       System.out.println("c : "+a+"\t"+b+"\t"+c);
   }

   public void doPrintAkurasi()
   {
       int pembilang = 0;
       int penyebut = 0;

       for(String s1 : hasil.keySet())
       {
           for(String s2 : hasil.get(s1).keySet())
           {
               if(s1.equals(s2))
               {
                   pembilang = pembilang + hasil.get(s1).get(s2);
               }
               penyebut = penyebut + hasil.get(s1).get(s2);
           }
       }

       //print
       double hasil = pembilang * 100 / penyebut;
       System.out.println("Akurasi: "+hasil+"%");
   }
}
